#region license
/*
 * Copyright (C) 2007 CchenSoft.com
 * 
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License 2.1 or later, as
 * published by the Free Software Foundation. See the included License.txt
 * or http://www.gnu.org/copyleft/lesser.html for details.
 * 
 * Author: Billy Zhang
 */
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Net;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Web;
using CchenSoft.Portal.Spi;
using CchenSoft.Portal.Spi.Registry;
using CchenSoft.Portal.Spi.Plugin;
using CchenSoft.Portal.Spi.Service;
using CchenSoft.Portal.Util;

namespace CchenSoft.Portal.Spi.Registry
{
    public class PluginRegistry
    {
        private static PluginRegistry instance = new PluginRegistry();

        private IDictionary<string, IHttpHandler> handlers;
        private IDictionary<string, IPlugin> plugins;
        private IDictionary<string, string> categories;

        private PluginRegistry()
        {
            handlers = new Dictionary<string, IHttpHandler>();
            plugins = new Dictionary<string, IPlugin>();
            categories = new Dictionary<string, string>();
        }

        public static PluginRegistry Instance
        {
            get { return instance; }
        }

        private string GetNodeValue(XmlNode node)
        {
            if (node == null)
                return "";

            if (node is XmlElement)
                return node.InnerText;
            else if (node is XmlAttribute)
                return node.Value;
            else
                return node.InnerText;
        }

        public IPlugin RegisterPlugin(string folder)
        {
            string folder2 = folder.ToLower();
            if (!folder2.EndsWith("\\"))
                folder2 += "\\";

            string configFile = folder2 + "plugin.config";
            FileInfo fi = new FileInfo(configFile);

            if (plugins.ContainsKey(folder2))
            {
                IPlugin plugin = plugins[folder2];
                if (fi.Exists)
                {
                    // update.
                    if (fi.LastWriteTime > plugin.LastWriteTime)
                        UnregisterPlugin(folder2);
                }
                else
                {
                    // delete.
                    UnregisterPlugin(folder2);
                }
            }

            if (!plugins.ContainsKey(folder2))
            {
                // add.
                if (!fi.Exists)
                    return null;

                BootLogger.Instance.Info("register plugin: " + folder2, this.GetType());

                XmlDocument doc = new XmlDocument();
                doc.Load(configFile);
                XmlNode node = doc.DocumentElement.SelectSingleNode("plugin-type");
                if (node != null && !string.IsNullOrEmpty(node.InnerText))
                {
                    Type pluginType = Type.GetType(node.InnerText);
                    IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
                    plugin.Folder = folder2;
                    plugin.Path = HttpUtil.ConvertFolderToPath(folder2);
                    plugin.LastWriteTime = fi.LastWriteTime;
                    plugin.Configure(doc);

                    foreach (HandlerEntry entry in plugin.Handlers)
                    {
                        IHttpHandler handler = (IHttpHandler)Activator.CreateInstance(entry.HandlerType);
                        handlers.Add(entry.Pattern, handler);
                    }

                    plugins[folder2] = plugin;
                }
            }

            return plugins[folder2];
        }

        public void UnregisterPlugin(string folder)
        {
            if (plugins.ContainsKey(folder))
            {
                IPlugin plugin = plugins[folder];
                //domainServices.Remove(entry);

                foreach (HandlerEntry entry in plugin.Handlers)
                    handlers.Remove(entry.Pattern);

                plugins.Remove(folder);

                BootLogger.Instance.Info("unregister module: " + folder, this.GetType());
            }
        }

        public IPlugin GetPlugin(string name)
        {
            string s = name.ToLower();

            foreach (IPlugin plugin in plugins.Values)
            {
                if (s.Equals(plugin.PluginId.ToLower()))
                    return plugin;
            }
            return null;
        }

        public IPlugin GetPluginByCategory(string category)
        {
            if (categories.ContainsKey(category))
                return GetPlugin(categories[category]);
            return null;
        }

        public void AddCategory(string category, string pluginName)
        {
            categories[category] = pluginName;
        }
    }
}
